﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GenericGA.extrandom;

namespace GenericGA.generationmaker.crossover
{
    /// <summary>
    /// Decorator for crossovers to make the crossover occur at a probability (crossover rate) rather than always.
    /// </summary>
    public class ProbabilisticCrossover : Crossover
    {

        /// <summary>
        /// A random number generator.
        /// </summary>
        private readonly ExtRandom randGen;

        /// <summary>
        /// The probability between 0 and 1 that a crossover will occur every time the Cross method is called.
        /// </summary>
        public double Rate
        {
            get
            {
                return rate;
            }
            set
            {
                if (rate < 0 || rate > 1)
                {
                    throw new ArgumentException();
                }
                rate = value;
            }
        }
        private double rate;

        /// <summary>
        /// The crossover that will occur.
        /// </summary>
        private readonly Crossover crossover;

        /// <summary>
        /// Constructor to create a ProbabiliticCrossover decorator from a crossover rate and a crossover object.
        /// </summary>
        /// <param name="randGen">A random number generator.</param>
        /// <param name="rate">The crossover rate.</param>
        /// <param name="crossover">The crossover to take place.</param>
        public ProbabilisticCrossover(ExtRandom randGen, double rate, Crossover crossover)
        {
            this.randGen = randGen;
            Rate = rate;
            this.crossover = crossover;
        }

        /// <summary>
        /// Cross the chromosomes or not depending on the crossover rate.
        /// </summary>
        /// <param name="bits1">A chromosome to cross.</param>
        /// <param name="bits2">A chromosome to cross.</param>
        public override void Cross(List<ulong> offspring1, List<ulong> offspring2)
        {
            if (randGen.NextBool(rate))
            {
                crossover.Cross(offspring1, offspring2);
            }
        }

    }
}
